/**
 * Created by quliang on 16-4-7 下午2:07.
 * Copyright (c) 2016 SAIZ.CN. All rights reserved.
 */

package com.example.db.utils;

import android.text.Editable;
import android.widget.EditText;

import com.example.db.common.SaizConstant;
import com.google.gson.JsonElement;

import org.springframework.core.convert.TypeDescriptor;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Map;


public final class ObjectUtil {


    public static boolean isEmpty(Object obj) {
        if (obj == null) {
            return true;
        }
        if (obj.getClass().isArray()) {
            return Array.getLength(obj) == 0;
        }
        if (obj instanceof Character) {
            Character ch = (Character) obj;
            return ch <= '\0' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '\f';
        }
        if (obj instanceof CharSequence) {
            return "".equals(obj.toString());
        }
        if (obj instanceof Collection) {
            return ((Collection) obj).isEmpty();
        }
        if (obj instanceof Map) {
            return ((Map) obj).isEmpty();
        }
        if (obj instanceof File) {
            return !((File) obj).isFile();
        }
        // other
        return false;
    }

    public static boolean isEquals(Object obj1, Object obj2) {
        if (obj1 instanceof String && obj2 instanceof String) {
            return obj1.equals(obj2);
        }
        if (obj1 instanceof Date && obj2 instanceof Date) {
            return ((Date) obj1).getTime() == ((Date) obj2).getTime();
        }
        // Character,Number,Null
        return obj1 == obj2;
    }

    public static void assertEmpty(Object obj, String text) {
        assertExpression(isEmpty(obj), text);
    }

    public static void assertNotEmpty(Object obj, String text) {
        assertExpression(!isEmpty(obj), text);
    }

    public static void assertExpression(boolean expression, String text) {
        if (!expression) {
            String message = MessageFormat.format(SaizConstant.ASSERT_EXPRESSION, text);
            throw new IllegalArgumentException(message);
        }
    }

    public static String toString(EditText editText, String defaultValue) {
        if (editText == null) {
            return defaultValue;
        }
        Editable text = editText.getText();
        String val = text.toString();
        if (isEmpty(val)) {
            return defaultValue;
        }
        return val;
    }

    /**
     * 将指定数组的指定范围复制到一个新数组。该范围的初始索引 (from) 必须位于 0 和 dataArray.length（包括）之间。
     *
     * @param array 将要从其复制一个范围的数组
     * @param from  要复制的范围的初始索引（包括）
     * @param to    要复制的范围的最后索引（不包括）。（此索引可能位于数组范围之外）。
     * @return 包含取自原数组指定范围的新数组，截取或用 false 元素填充以获得所需长度
     */
    public static Object copyArray(Object array, int from, int to) {
        int newLength = to - from;
        if (newLength < 0)
            throw new IllegalArgumentException(from + " > " + to);
        int len = Array.getLength(array);
        Class<?> ct = array.getClass().getComponentType();
        Object copy = Array.newInstance(ct, newLength);
        System.arraycopy(array, from, copy, 0, Math.min(len - from, newLength));
        return copy;
    }

    /**
     * 深度克隆
     *
     * @param src 对象源
     * @param <E> 对象类型
     * @return 克隆对象
     */
    @SuppressWarnings("unchecked")
    private static <E extends Serializable> E cloneBean(E src) throws Exception {
        if (!Serializable.class.isInstance(src)) {
            throw new NotSerializableException();
        }

        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oo = new ObjectOutputStream(bo);
            oo.writeObject(src);
            ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
            ObjectInputStream oi = new ObjectInputStream(bi);
            return (E) oi.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 批量转换String数组
     *
     * @param objects 数据
     * @return String数组
     */
    public static String[] batchConvert(Object... objects) {
        String[] cs = new String[objects.length];
        for (int i = 0; i < objects.length; i++) {
            if (objects[i].getClass().isAssignableFrom(Date.class)) {
                cs[i] = DateUtil.format((Date) objects[i]);
            } else {
                cs[i] = objects[i].toString();
            }
        }
        return cs;
    }

    /**
     * 将value转换成字符串
     *
     * @param value 值
     * @return 转换的字符串
     */
    public static String toString(Object value) {
        if (value == null) {
            return null;
        }
        Class<?> klass = value.getClass();
        if (klass.isArray()) {
            return JsonUtil.getJsonString(value);
        }
        if (value instanceof Date) {
            return DateUtil.format((Date) value);
        }
        if (value instanceof File) {
            return ((File) value).getPath();
        }
        if (value instanceof StringWriter ||
                value instanceof ByteArrayOutputStream) {
            return value.toString();
        }
        if (value instanceof Character ||
                value instanceof CharSequence ||
                value instanceof Number) {
            return String.valueOf(value);
        }
        return JsonUtil.getJsonString(value);
    }

    public static Object toObject(TypeDescriptor descriptor, Object value) {
        if (isEmpty(value) || descriptor == null) {
            return null;
        }
        Class<?> klass = descriptor.getType();
        if (Number.class.isAssignableFrom(klass) ||
                Character.class.isAssignableFrom(klass) ||
                CharSequence.class.isAssignableFrom(klass)) {
            return value;
        }
        JsonElement je = JsonUtil.getJsonElement(value.toString());
        return JsonUtil.getJsonObject(je, getRawType(descriptor));
    }

    private static Class<?> getRawType(TypeDescriptor descriptor) {
        if (descriptor.isArray() || descriptor.isCollection()) {
            return getRawType(descriptor.getElementTypeDescriptor());
        }
        return descriptor.getType();
    }
}
